package com.yk.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yk.api.system.dto.DeviceRoleAlarmDTO;
import com.yk.api.system.dto.DeviceRoleDTO;
import com.yk.common.core.constant.CacheConstants;
import com.yk.common.core.constant.NumberConstant;
import com.yk.common.core.domain.BasePageQuery;
import com.yk.common.core.enums.DeviceControlsTypeEnum;
import com.yk.common.core.enums.DeviceRoleStatusEnum;
import com.yk.common.core.enums.RoleTypeEnum;
import com.yk.common.core.exception.ServiceException;
import com.yk.common.core.utils.LoginHelper;
import com.yk.common.redis.service.RedisService;
import com.yk.system.entity.*;
import com.yk.system.mapper.*;
import com.yk.system.service.CustomerInfoService;
import com.yk.system.service.DeviceRoleService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 设备权限表 服务类
 *
 * @author lmx
 * @since 2023-11-08
 */
@Service
@RequiredArgsConstructor
public class DeviceRoleServiceImpl extends ServiceImpl<DeviceRoleMapper, DeviceRole> implements DeviceRoleService {

    private final UserMapper userMapper;
    private final AlarmUserDeviceMapper alarmUserDeviceMapper;
    private final DeviceRoleMapper deviceRoleMapper;
    private final VariableMapper variableMapper;
    private final RedisService redisService;
    private final CustomerInfoService customerInfoService;

    @Override
    public DeviceRole initDeviceRole(Long deviceId) {
        Long loginUserId = LoginHelper.getLoginUserId();
        DeviceRole deviceRole = new DeviceRole();
        deviceRole.setDeviceId(deviceId);
        deviceRole.setAdminId(loginUserId);
        deviceRole.setUserId(loginUserId);
        deviceRole.setRoleType(RoleTypeEnum.ADMIN.getCode());
        deviceRole.setStatus(DeviceRoleStatusEnum.SHARING.getCode());
        return deviceRole;
    }

    @Override
    public void save2Device(DeviceRole deviceRole) {
        baseMapper.insert(deviceRole);
    }

    @Override
    public void assignDeviceRole(DeviceRoleDTO deviceRoleDTO) {
        if (Objects.isNull(deviceRoleDTO)) {
            return;
        }
        if (Objects.nonNull(deviceRoleDTO.getUserId())) {
            User user = userMapper.selectById(deviceRoleDTO.getUserId());
            if (Objects.nonNull(user)) {
                deviceRoleDTO.setUserName(user.getNickName());
                deviceRoleDTO.setPhone(user.getPhone());
                String companyName = customerInfoService.getCompanyNameByPhone(user.getPhone());
                deviceRoleDTO.setCorporationName(companyName);
            }
        }
        Date dateTime = DateUtil.parseDateTime("9999-12-31 00:00:00");
        if (Objects.nonNull(deviceRoleDTO.getExpiredTime()) &&
                DateUtil.isSameDay(dateTime, deviceRoleDTO.getExpiredTime())) {
            deviceRoleDTO.setExpiredTime(null);
        }
    }

    @Override
    public void checkDeviceRole(DeviceControlsTypeEnum typeEnum, Long deviceId) {
        Long loginUserId = LoginHelper.getLoginUserId();
        LambdaQueryWrapper<DeviceRole> lambda = new LambdaQueryWrapper<>();
        lambda.eq(DeviceRole::getUserId, loginUserId);
        lambda.eq(DeviceRole::getDeviceId, deviceId);
        lambda.eq(DeviceRole::getStatus, NumberConstant.ZERO_STR);
        DeviceRole deviceRole = baseMapper.selectOne(lambda);
        if (Objects.isNull(deviceRole)) {
            throw new ServiceException("您没有权限操作该设备");
        }
        RoleTypeEnum.checkDeviceRole(typeEnum, deviceRole.getRoleType());
    }

    @Override
    public DeviceRole getDeviceRole(Long deviceId) {
        Long loginUserId = LoginHelper.getLoginUserId();
        LambdaQueryWrapper<DeviceRole> lambda = new LambdaQueryWrapper<>();
        lambda.eq(DeviceRole::getUserId, loginUserId);
        lambda.eq(DeviceRole::getDeviceId, deviceId);
        lambda.eq(DeviceRole::getStatus, NumberConstant.ZERO_STR);
        return baseMapper.selectOne(lambda);
    }

    @Override
    public List<DeviceRoleDTO> pageByTime(Long deviceId) {
        DeviceRole deviceRole = getDeviceRole(deviceId);
        if (Objects.isNull(deviceRole)) {
            return CollUtil.newArrayList();
        }
        if (!RoleTypeEnum.ADMIN.getCode().equals(deviceRole.getRoleType()) && !RoleTypeEnum.MANAGE.getCode().equals(deviceRole.getRoleType())) {
            return CollUtil.newArrayList();
        }
        return baseMapper.pageByTime(deviceId);
    }

    @Override
    public void saveDeviceRole(DeviceRole deviceRole) {
        long id = IdWorker.getId();
        deviceRole.setId(id);
        Date now = new Date();
        if (Objects.nonNull(deviceRole.getExpiredTime())) {
            if (now.after(deviceRole.getExpiredTime())) {
                throw new ServiceException("不能选择已过期的时间");
            }
            // 计算过期时间
            Date dateTime = DateUtil.parseDateTime("9999-12-31 00:00:00");
            if (Objects.nonNull(deviceRole.getExpiredTime()) &&
                    !DateUtil.isSameDay(dateTime, deviceRole.getExpiredTime())) {
                Date expiredTime = deviceRole.getExpiredTime();
                long time = DateUtil.between(now, expiredTime, DateUnit.MINUTE);
                redisService.setCacheObject(CacheConstants.DEVICE_ROLE_EXPIRED_TIME_KEY + id, id, time, TimeUnit.MINUTES);
            }
        }
        baseMapper.insert(deviceRole);
    }

    @Override
    public void updateDelDeviceRole(DeviceRole deviceRole) {
        baseMapper.updateById2Del(deviceRole);
        // 计算过期时间
        Date dateTime = DateUtil.parseDateTime("9999-12-31 00:00:00");
        if (Objects.nonNull(deviceRole.getExpiredTime()) &&
                !DateUtil.isSameDay(dateTime, deviceRole.getExpiredTime())) {
            Date expiredTime = deviceRole.getExpiredTime();
            long time = DateUtil.between(new Date(), expiredTime, DateUnit.MINUTE);
            redisService.setCacheObject(CacheConstants.DEVICE_ROLE_EXPIRED_TIME_KEY + deviceRole.getId(), deviceRole.getId(), time, TimeUnit.MINUTES);
        }
    }

    @Override
    public void updateDeviceRole(DeviceRole deviceRole) {
        // 计算过期时间
        Date dateTime = DateUtil.parseDateTime("9999-12-31 00:00:00");
        if (Objects.nonNull(deviceRole.getExpiredTime()) &&
                !DateUtil.isSameDay(dateTime, deviceRole.getExpiredTime())) {
            Date expiredTime = deviceRole.getExpiredTime();
            long time = DateUtil.between(new Date(), expiredTime, DateUnit.MINUTE);
            redisService.setCacheObject(CacheConstants.DEVICE_ROLE_EXPIRED_TIME_KEY + deviceRole.getId(), deviceRole.getId(), time, TimeUnit.MINUTES);
        }
        baseMapper.updateById(deviceRole);
    }

    @Override
    public void update2Status(String id) {
        DeviceRole deviceRole = baseMapper.selectById(id);
        if (Objects.nonNull(deviceRole)) {
            deviceRole.setStatus(NumberConstant.ONE_STR);
            baseMapper.updateById(deviceRole);
        }
    }

    @Override
    public DeviceRole getByIdIgnoreDel(Long id) {
        return baseMapper.getByIdIgnoreDel(id);
    }

    public void checkShare(Long deviceId, String message, Long userId) {
        LambdaQueryWrapper<DeviceRole> lambda = new LambdaQueryWrapper<>();
        lambda.eq(DeviceRole::getUserId, userId);
        lambda.eq(DeviceRole::getDeviceId, deviceId);
        lambda.eq(DeviceRole::getStatus, NumberConstant.ZERO_STR);
        DeviceRole viewDeviceRole = baseMapper.selectOne(lambda);
        Assert.isNull(viewDeviceRole, message);
    }

    @Override
    public List<Long> selectByDeviceIdAdmin(Long deviceId) {
        LambdaQueryWrapper<DeviceRole> deviceLambda = new LambdaQueryWrapper<>();
        deviceLambda.select(DeviceRole::getUserId);
        deviceLambda.eq(DeviceRole::getDeviceId, deviceId);
        deviceLambda.eq(DeviceRole::getStatus, NumberConstant.ZERO_STR);
        deviceLambda.in(DeviceRole::getRoleType, CollUtil.newArrayList("3", "4"));
        List<DeviceRole> list = this.list(deviceLambda);
        if (CollUtil.isNotEmpty(list)) {
            return list.stream().map(DeviceRole::getUserId).collect(Collectors.toList());

        }
        return null;
    }

    @Override
    public IPage<DeviceRoleAlarmDTO> page2Alarm(BasePageQuery<DeviceRoleAlarmDTO> pageParam) {
        Long userId = LoginHelper.getLoginUserId();
        List<Integer> types;
        DeviceRoleAlarmDTO param = pageParam.getParam();
        if (Objects.isNull(param.getType())) {
            types = CollUtil.newArrayList(3, 4);
        } else {
            types = CollUtil.newArrayList(param.getType());
        }
        List<Device> deviceList = deviceRoleMapper.selectDeviceByUserIdAndType(userId, types);
        if (CollUtil.isEmpty(deviceList)) {
            return new Page<>();
        }
        param.setDeviceIds(deviceList.stream().map(Device::getId).collect(Collectors.toList()));
        param.setTempIds(deviceList.stream().map(Device::getTemplateId).collect(Collectors.toList()));
        IPage<DeviceRoleAlarmDTO> iPage = baseMapper.page2Alarm(new Page<>(pageParam.getPageNum(), pageParam.getPageSize()), pageParam.getParam());
        if (CollUtil.isEmpty(iPage.getRecords())) {
            return iPage;
        }
        iPage.getRecords().forEach(it -> {
            Variable variable = variableMapper.selectById(it.getVariableId());
            if (Objects.nonNull(variable)) {
                it.setVariableName(variable.getName());
            }
            User user = userMapper.selectById(it.getUserId());
            if (Objects.nonNull(user)) {
                it.setUserName(user.getNickName());
            }
            AlarmUserDevice alarmUserDevice = alarmUserDeviceMapper.selectByUserAndDevice(userId,
                    it.getDeviceId(), it.getVariableId(), it.getAlarmId());
            if (Objects.nonNull(alarmUserDevice)) {
                it.setUserAlarmId(alarmUserDevice.getId());
                it.setUserInformType(alarmUserDevice.getInformType());
            }
        });
        return iPage;
    }
}